feat(drivers): NIBE S-series local REST API driver + opt-in HTTP TLS cert pinning#530
Conversation
…cert pinning Add drivers/nibe_local.lua — read-only NIBE S-series telemetry over the on-prem Local REST API (HTTPS + Basic auth, self-signed cert pinned). It auto-detects the serial, pulls the full ~980-point register map in one request, and emits every point with exact per-point divisor scaling plus the myUplink-compatible hp_* headline metrics so the heating dashboard works with either source. Read-only; self-heals device detection. Add opt-in TLS certificate pinning to the Lua HTTP host capability (capabilities.http.tls_pin_sha256): pins a self-signed endpoint's leaf cert by SHA-256 so a driver can reach it without disabling verification. A swapped cert (LAN MITM) is rejected at the handshake. Drivers without a pin keep standard system-root verification — unchanged for all existing HTTP drivers. Verified live against a real NIBE S735 plus hermetic + unit tests (pin accept/reject/no-pin/malformed + fingerprint normalization). Co-Authored-By: HuggeK <[email protected]>
Resolve the hp_* headline variable-ids per pump from a built-in PROFILES map keyed by product.name/firmwareId (generic S-series default, verified on S735), refined right after device detection. Config overrides (param_*_id) still win (override > profile > default). One driver now covers the whole S-series with no per-model code; add a PROFILES entry only for a model confirmed to renumber a headline. Co-Authored-By: HuggeK <[email protected]>
…'NIBE REST API S-series' host.emit_metric gains an optional 4th arg, register — a source address (e.g. a Modbus register id) carried into the live metric snapshot (telemetry MetricSnapshot.Register, json "register"). It's generic: any driver with addressable points can pass it; existing 3-arg callers are unaffected (ocpp + tests updated to the explicit 5-arg Store.EmitMetric form). The NIBE driver reads metadata.modbusRegisterID per point and passes it for every emitted signal — canonical aliases (hp_power_w -> reg 1048) and auto-named metrics alike — so the per-driver 'all signals' detail view can show a Register column. Menu-only points (register 0 / absent) emit "" so the column stays blank rather than showing a misleading 0. Also renames the driver's UI display name to 'NIBE REST API S-series'. Co-Authored-By: HuggeK <[email protected]>
eb63a1a to
a5869de
Compare
parseRange capped at 3d, so the heat-pump month temp graph (30d) and the energy-period windows (7d/30d/366d) silently fell back to 5m. Add a generic '<N><unit>' parser (m/h/d/w/y) after the existing fixed cases, capped at 2y to bound the TS-DB scan. Existing exact ranges are unchanged. Co-Authored-By: HuggeK <[email protected]>
Future work: optional writable mode — Solar PV / smart-energy controlThe driver is read-only today (by design). When/if we add an opt-in writable path, the NIBE local API exposes a useful set of Solar PV control holding registers that would let 42w push live PV surplus into the pump (so it stores free solar as heat / hot water / pool instead of exporting):
|
The network scan only dialed Modbus 502 / MQTT 1883 / HTTP 80, so a NIBE S-series pump — reachable, but serving its Local REST API on 8443 — never appeared in Settings -> Scan or the setup wizard. Add 8443 (https) to the probe set. Co-Authored-By: HuggeK <[email protected]>
host.emit_metric gains an optional 5th title arg (the device's own point
label). It threads through metricSnap -> MetricSnapshot -> /api/drivers/{name}
so the heat-pump all-signals view can show a plain-language clarification under
each of the ~960 raw signals. The NIBE driver passes pt.title; all other
EmitMetric callers pass "" (ocpp, tests).
Co-Authored-By: HuggeK <[email protected]>
🔗 Paired with #532 (dashboard UI)This driver is the data source; the dashboard UI that renders its telemetry is #532. Best reviewed / merged together:
Without #530 the card has no data; without #532 the telemetry has no UI. |
|
Now out of draft (together with the UI PR #532 and the Hugin packaging PR srcfl/hugin-drivers#7). The opt-in writable follow-up — feeding live PV production into the pump's Solar PV registers (2107/2108/2109), later a power cap for the electric add-heat — is planned in #537. |
frahlg
left a comment
There was a problem hiding this comment.
Reviewed driver boundary, TLS pinning, telemetry/storage behavior, configuration, and tests. Added maintainer fixes so configured pins fail closed and cannot downgrade to HTTP, the ~980-point map records changes plus bounded full snapshots instead of duplicate rows every minute, sanitized-name collisions are stable, and range parsing cannot overflow. Local verify-all and GitHub CI are green.
Summary
Adds a read-only NIBE S-series heat-pump driver (
drivers/nibe_local.lua) that reads the pump's on-prem Local REST API over the LAN — no cloud, no OAuth — plus opt-in TLS certificate pinning for the Lua HTTP host capability.Driver
hp_*headline metrics as the MyUplink cloud driver (hp_power_w,hp_hw_top_temp_c,hp_outdoor_temp_c, …) so the heating dashboard works with either source.hp_<name>names.Host: opt-in cert pinning
capabilities.http.tls_pin_sha256pins an HTTPS endpoint's leaf certificate by SHA-256, so a driver can reach a self-signed endpoint (the pump) by trusting exactly one certificate — a swapped cert (LAN MITM) is rejected at the handshake — instead of disabling verification.Verification
go build ./...,go vet, gofmt clean.Companion public-driver PR opened against
srcfl/hugin-drivers.🤖 Generated with Claude Code